package jxd.myDwr;

import java.io.IOException;
import java.io.PrintWriter;
import java.io.Serializable;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.directwebremoting.ScriptBuffer;
import org.directwebremoting.WebContextFactory;

import jxd.myDwr.EnginePrivate;

import org.directwebremoting.extend.MarshallException;
import org.directwebremoting.extend.Marshaller;
import org.directwebremoting.extend.RealScriptSession;
import org.directwebremoting.extend.Replies;
import org.directwebremoting.extend.Reply;
import org.directwebremoting.extend.ScriptBufferUtil;
import org.directwebremoting.extend.ScriptConduit;
import org.directwebremoting.util.DebuggingPrintWriter;

public abstract class BaseCallMarshaller extends org.directwebremoting.dwrp.BaseCallMarshaller
  implements Marshaller,Serializable
{
  public void marshallOutbound(Replies replies, HttpServletRequest request, HttpServletResponse response)
    throws IOException
  {
    response.setContentType(getOutboundMimeType());
    PrintWriter out;
    if (log.isDebugEnabled())
    {
      out = new DebuggingPrintWriter("", response.getWriter());
    }
    else
    {
      out = response.getWriter();
    }

    ScriptConduit conduit = new CallScriptConduit(out);

    if ((out instanceof DebuggingPrintWriter))
    {
      DebuggingPrintWriter dpw = (DebuggingPrintWriter)out;
      dpw.setPrefix("out(" + conduit.hashCode() + "): ");
    }

    sendOutboundScriptPrefix(out, replies.getBatchId());

    RealScriptSession scriptSession = (RealScriptSession)WebContextFactory.get().getScriptSession();

    out.println("//#DWR-INSERT");
    scriptSession.writeScripts(conduit);
    out.println("//#DWR-REPLY");

    String batchId = replies.getBatchId();
    for (int i = 0; i < replies.getReplyCount(); i++)
    {
      Reply reply = replies.getReply(i);
      String callId = reply.getCallId();
      try
      {
        if (reply.getThrowable() != null)
        {
          Throwable ex = reply.getThrowable();
          EnginePrivate.remoteHandleException(conduit, batchId, callId, ex);

          log.warn("--Erroring: batchId[" + batchId + "] message[" + ex.toString() + ']');
        }
        else
        {
          Object data = reply.getReply();
          EnginePrivate.remoteHandleCallback(conduit, batchId, callId, data);
        }

      }
      catch (IOException ex)
      {
        log.error("--Output Error: batchId[" + batchId + "] message[" + ex.toString() + ']', ex);
      }
      catch (MarshallException ex)
      {
        EnginePrivate.remoteHandleMarshallException(conduit, batchId, callId, ex);
        log.warn("--MarshallException: batchId=" + batchId + " class=" + ex.getConversionType().getName(), ex);
      }
      catch (Exception ex)
      {
        EnginePrivate.remoteHandleException(conduit, batchId, callId, ex);
        log.error("--MarshallException: batchId=" + batchId + " message=" + ex.toString());
      }
    }

    sendOutboundScriptSuffix(out, replies.getBatchId());
  }
  protected class CallScriptConduit extends ScriptConduit
  {
    private final PrintWriter out;

    protected CallScriptConduit(PrintWriter out)
    {
      super(ScriptConduit.RANK_FAST);
      if (out == null)
      {
        throw new NullPointerException("out=null");
      }

      this.out = out;
    }

    public boolean addScript(ScriptBuffer script)
      throws IOException, MarshallException
    {
      BaseCallMarshaller.this.sendScript(this.out, ScriptBufferUtil.createOutput(script, BaseCallMarshaller.this.converterManager));
      return true;
    }
  }
}